﻿//-------------------------------------
// WBFSSync - WBFSSync.exe
//
// Copyright 2009 Caian (ÔmΣga Frøst) <frost.omega@hotmail.com> :
//
// WBFSSync is Licensed under the terms of the Microsoft Reciprocal License (Ms-RL)
//
// OperationListView.cs:
//
// Classe que exibe o progresso das operações de arquivo do programa
//
//-------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace WBFSSync.AeroControls
{
    class OperationListView : ListView
    {
        //----------------- Classes / Estruturas

        class OperationListViewItemSorter : IComparer
        {
            OperationListView Parent;
            public OperationListViewItemSorter(OperationListView parent)
            {
                Parent = parent;
            }

            #region IComparer Members

            public int Compare(object x, object y)
            {
                Operation a = (Operation)(x as ListViewItem).Tag;
                Operation b = (Operation)(y as ListViewItem).Tag;

                if (Parent.Sorting == SortOrder.Descending)
                    return (int)(a.Progress.Percentage - b.Progress.Percentage);
                else
                    return (int)(b.Progress.Percentage - a.Progress.Percentage);
            }

            #endregion
        }

        //----------------- Variáveis
        
        Timer timer = new Timer();
        int operationCount = 0;

        Color GrayColor = Color.FromArgb(109, 109, 109);
        Brush BackgroundBrush;

        //----------------- Rotinas

        public OperationListView() : base()
        {
            DoubleBuffered = true;
            OwnerDraw = true;
            View = View.Details;
            BackgroundBrush = new SolidBrush(BackColor);

            ListViewItemSorter = new OperationListViewItemSorter(this);

            timer.Interval = 300;
            timer.Tick += new EventHandler(timer_Tick);
            timer.Enabled = false;
        }

        //----------------- Overrides

        protected override void OnBackColorChanged(EventArgs e)
        {
            BackgroundBrush = new SolidBrush(BackColor);
            base.OnBackColorChanged(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            Invalidate();
            base.OnMouseLeave(e);
        }
        
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            if ((e.Button != MouseButtons.Left) || (SelectedItems.Count != 1)) return;

            if (MessageBox.Show(this, Language.message_canceloperation, Language.AppName, MessageBoxButtons.YesNo,
                MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
            {
                Operation operation = (Operation)SelectedItems[0].Tag;
                operation.Progress.Cancel = true;
            }

            base.OnMouseDoubleClick(e);
        }

        protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
        {
            e.Graphics.FillRectangle(BackgroundBrush, e.Bounds);

            e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
            e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            DrawSubItemBackground(e);

            String text = "";
            StringFormat format = new StringFormat();
            format.Trimming = StringTrimming.EllipsisCharacter;
            format.LineAlignment = StringAlignment.Near;
            format.Alignment = StringAlignment.Near;

            if (e.ColumnIndex == 0)
            {
                text = e.Item.Text;
            }
            else
            {
                Operation op = (Operation)e.Item.Tag;
                if (e.ColumnIndex == 1)
                {
                    text = op.SourcePath;
                }
                else if (e.ColumnIndex == 2)
                {
                    text = op.DestinationPath;
                }
                else if (e.ColumnIndex == 3)
                {
                    if (op.Progress.Cancel)
                    {
                        text = Language.opstate_cancel;
                    }
                    else
                    {
                        if (op.Waiting)
                        {
                            text = Language.opstate_pending;
                        }
                        else
                        {
                            DrawSubItemProgressBar(e);
                            text = op.Progress.Ratio.ToString("P01");
                            format.Alignment = StringAlignment.Far;
                        }
                    }
                }
            }

            if (text.Length != 0)
            {
                RectangleF bounds = new RectangleF(e.Bounds.Left + 4,
                e.Bounds.Top + (e.Bounds.Height - Skin.IconTitleFont.Height) / 2, Columns[e.ColumnIndex].Width - 5,
                Skin.IconTitleFont.Height);

                e.Graphics.DrawString(text, Skin.IconTitleFont, Brushes.Black, bounds, format);
            }

            base.OnDrawSubItem(e);
        }

        protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
            base.OnDrawColumnHeader(e);
        }

        //----------------- Desenho

        void DrawSubItemBackground(DrawListViewSubItemEventArgs e)
        {
            Boolean first = (e.ColumnIndex == 0);
            Boolean last = (e.ColumnIndex == e.Item.SubItems.Count - 1);

            if ((Columns.Count == 1) || (e.Item.SubItems.Count == 1)) //Único sub-item
            {
                if ((e.ItemState & ListViewItemStates.Selected) != (ListViewItemStates)0)
                {
                    e.Graphics.DrawImage(Skin.explorer_detail_selection_l_c, e.Bounds.X, e.Bounds.Y, 3, e.Bounds.Height);
                    e.Graphics.DrawImage(Skin.explorer_detail_selection_m_c, e.Bounds.X + 3, e.Bounds.Y, e.Bounds.Width - 6, e.Bounds.Height);
                    e.Graphics.DrawImage(Skin.explorer_detail_selection_r_c, e.Bounds.Right - 3, e.Bounds.Y, 3, e.Bounds.Height);
                }
            }
            else
            {
                if (first) //Primeiro: borda da esquerda + meio
                {
                    if ((e.ItemState & ListViewItemStates.Selected) != (ListViewItemStates)0)
                    {
                        e.Graphics.DrawImage(Skin.explorer_detail_selection_l_c, e.Bounds.X, e.Bounds.Y, 3, e.Bounds.Height);
                        e.Graphics.DrawImage(Skin.explorer_detail_selection_m_c, e.Bounds.X + 3, e.Bounds.Y, e.Bounds.Width - 3, e.Bounds.Height);
                    }
                }
                else if (last) //Último: meio + borda da direita
                {
                    int widthadd = 0;
                    for (int i = e.ColumnIndex + 1; i < Columns.Count; i++) widthadd += Columns[i].Width;

                    if ((e.ItemState & ListViewItemStates.Selected) != (ListViewItemStates)0)
                    {
                        e.Graphics.DrawImage(Skin.explorer_detail_selection_m_c, e.Bounds.X, e.Bounds.Y, e.Bounds.Width + widthadd - 3, e.Bounds.Height);
                        e.Graphics.DrawImage(Skin.explorer_detail_selection_r_c, e.Bounds.Right + widthadd - 3, e.Bounds.Y, 3, e.Bounds.Height);
                    }
                }
                else //Meio: meio (lol)
                {
                    if ((e.ItemState & ListViewItemStates.Selected) != (ListViewItemStates)0)
                    {
                        e.Graphics.DrawImage(Skin.explorer_detail_selection_m_c, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
                    }
                }
            }
        }

        void DrawSubItemProgressBar(DrawListViewSubItemEventArgs e)
        {
            Operation op = (Operation)e.Item.Tag;

            int progress_x = 4;
            int progress_y = e.Bounds.Top + (e.Bounds.Height - Skin.progresscontainer_l.Height) / 2;
            int progress_width = e.Bounds.Width - 5 - progress_x - 45;

            int progress_bar_width = (int)(op.Progress.Ratio * (progress_width - 2));

            progress_x += e.Bounds.X;

            e.Graphics.DrawImage(Skin.progresscontainer_l, progress_x, progress_y, 4, 13);
            e.Graphics.DrawImage(Skin.progresscontainer_m, progress_x + 4, progress_y, progress_width - 8, 13);
            e.Graphics.DrawImage(Skin.progresscontainer_r, progress_x + progress_width - 4, progress_y, 4, 13);
            e.Graphics.DrawImage(Skin.progressbar_green, progress_x + 1, progress_y + 1, progress_bar_width, 11);
        }

        //----------------- Misc

        public void AddOperation(Operation operation)
        {
            ListViewItem item = new ListViewItem();
            item.Name = operation.UniqueID.ToString();
            item.Text = FormatOperationName(operation.Type);
            item.Tag = operation;

            item.SubItems.Add(""); //Origem
            item.SubItems.Add(""); //Destino
            item.SubItems.Add(""); //Barra de progresso

            Items.Add(item);

            if (!timer.Enabled) timer.Enabled = true;
            operationCount++;
            
            Sort();
        }

        public void RemoveOperation(Operation operation)
        {
            //Operações não marcadas como "Delete" vão falhar
            try
            {
                Items[operation.UniqueID.ToString()].Remove();
                if (--operationCount == 0) timer.Enabled = false;
            }
            catch
            {
            }
        }
        
        //

        void timer_Tick(object sender, EventArgs e)
        {
            this.Invalidate();
            Sort();
        }

        public string FormatOperationName(OperationType optype)
        {
            switch (optype)
            {
                case OperationType.Copy: return Language.opname_copy;
                case OperationType.Move: return Language.opname_move;
                case OperationType.Delete: return Language.opname_delete;
                case OperationType.DiscDataChange: return Language.opname_delete;
                case OperationType.RarDecompress: return Language.opname_rardecompress;
                case OperationType.ScrubDecompress: return Language.opname_scrubdecompress;
                case OperationType.ScrubCompress: return Language.opname_scrubcompress;
                case OperationType.Format: return Language.opname_format;
                case OperationType.DeviceCloning: return Language.opname_devicecloning;
                case OperationType.CoverDownload: return Language.opname_coverdownload;
                case OperationType.ProgramUpdate: return Language.opname_programupdate;
                default: return Language.opname_unknown;
            }
        }
    }
}
